package com.topscomm.file.convert.ffmpeg;

import java.io.File;
import java.io.IOException;

import com.topscomm.basic.exception.ServiceException;
import com.topscomm.tap.common.ParameterCache;

import lombok.extern.slf4j.Slf4j;
import net.bramp.ffmpeg.FFmpeg;
import net.bramp.ffmpeg.FFmpegExecutor;
import net.bramp.ffmpeg.builder.FFmpegBuilder;
import net.bramp.ffmpeg.job.FFmpegJob;

/**
 * 视频转换
 * 
 * @description:
 * @author: donghang
 * @date: 2021年3月17日上午9:24:23
 * @modify:
 */
@Slf4j
public class FfmpegFileVideoConvert extends AbstractFFmpegFileConvert {
	private static FfmpegFileVideoConvert ffmpegFileVideoConvert = null;

	private FfmpegFileVideoConvert() {

	}

	/**
	 * 
	 * @description:
	 * @return
	 * @author: donghang
	 * @date: 2021年3月17日上午9:35:25
	 * @modify:
	 */
	public static FfmpegFileVideoConvert getInstance() {
		if (ffmpegFileVideoConvert == null) {
			ffmpegFileVideoConvert = new FfmpegFileVideoConvert();
		}
		return ffmpegFileVideoConvert;
	}

	/**
	 * 
	 * @description:
	 * @param filePath
	 * @param targetPath
	 * @return
	 * @author: donghang
	 * @date: 2021年3月17日上午9:24:35
	 * @modify:
	 */
	public String videoToHls(String inputFilePath, String targetPath) {
		// 切片文件夹
		File sourceFile = new File(inputFilePath);
		File outputDir = new File(targetPath);
		if (!outputDir.exists()) {
			outputDir.mkdirs(); // 创建目录
		}
		// 建造者模式分片处理
		String tempFilePath = targetPath + "/output.ts";
		String tempMp3FilePath = targetPath + "/output.mp3";
		String targetFilePath = targetPath + "/output_%d.ts";
		String m3u8FilePath = targetPath + "/output.m3u8";
		String tsFolderPath = targetPath + "/video/";
		File tsFoldeDir = new File(tsFolderPath);
		if (!tsFoldeDir.exists()) {
			tsFoldeDir.mkdirs(); // 创建目录
		}
		try {
			// 1.判断是否需要转换
			FFmpegBuilder builder = null;
			FFmpegExecutor executor = null;
			FFmpegJob job = null;
			String convertMp3FileParams = ParameterCache.getValue("FileAudioSpliceConvertFile", "aac");
			String inputFileExtension = inputFilePath.substring(inputFilePath.lastIndexOf(".") + 1,
					inputFilePath.length());
			if (convertMp3FileParams.toLowerCase().contains(inputFileExtension.toLowerCase())) {
				builder = new FFmpegBuilder().addInput(inputFilePath).overrideOutputFiles(true)
						.addOutput(tempMp3FilePath).addExtraArgs("-acodec", "libmp3lame").done();
				executor = new FFmpegExecutor(new FFmpeg(this.ffmpegPath));
				job = executor.createJob(builder, progress -> System.out.println("Progress: " + progress));
				job.run();
				// 2.首先切片成ts
				builder = new FFmpegBuilder().addInput(tempMp3FilePath).overrideOutputFiles(true)
						.addOutput(tempFilePath).addExtraArgs("-vcodec", "copy", "-acodec", "copy").done();
			} else {
				// 2.首先切片成ts
				builder = new FFmpegBuilder().addInput(inputFilePath).overrideOutputFiles(true).addOutput(tempFilePath)
						.addExtraArgs("-vcodec", "copy", "-acodec", "copy").done();
			}
			executor = new FFmpegExecutor(new FFmpeg(this.ffmpegPath));
			job = executor.createJob(builder, progress -> System.out.println("Progress: " + progress));
			job.run();
			File tempMp3File = new File(tempMp3FilePath);
			if (tempMp3File.exists()) {
				tempMp3File.delete();
			}
			if (job.getState() == FFmpegJob.State.FINISHED) {
				// 3.ts切片成hls "-hls_playlist_type", "vod",
				builder = new FFmpegBuilder().addInput(tempFilePath).overrideOutputFiles(true).addOutput(m3u8FilePath)
						.addExtraArgs("-c", "copy", "-f", "hls", "-hls_list_size", "0", "-hls_time", this.duration,
								"-hls_key_info_file", this.encPath, "-hls_segment_filename", targetFilePath)
						.done();
				executor = new FFmpegExecutor(new FFmpeg(this.ffmpegPath));
				job = executor.createJob(builder, progress -> System.out.println("Progress: " + progress));
				job.run();
				String prefix = String.format("%s/%s/%s/splice/", rootUrlTag, this.playRelativePath,
						sourceFile.getParent());
				// fileEncrypt(m3u8FilePath, "");
				fileEncrypt(m3u8FilePath, prefix);
				return m3u8FilePath;
			}
		} catch (IOException e) {
			log.error("ffmpeg切片异常" + e.getMessage());
			throw new ServiceException(e.getMessage());
		}
		return null;
	}

	/**
	 * 视频转MP4
	 * 
	 * @description:
	 * @param inputFilePath
	 * @param tsFolderPath
	 * @param imagePrefix
	 * @return
	 * @author: donghang
	 * @date: 2021年4月8日下午3:41:17
	 * @modify:
	 */
	public String videoToMp4(String inputFilePath, String tsFolderPath, String videoPrefix) {
		// 切片文件夹
		File outputDir = new File(tsFolderPath);
		if (!outputDir.exists()) {
			outputDir.mkdirs(); // 创建目录
		}
		try {
			FFmpegBuilder builder = null;
			FFmpegExecutor executor = null;
			FFmpegJob job = null;
			builder = new FFmpegBuilder().addInput(inputFilePath).overrideOutputFiles(true)
					.addOutput(tsFolderPath + "/" + videoPrefix + ".mp4")
					.addExtraArgs("-c:v", "libx265", "-preset", "ultrafast", "-crf", "25", "-tag:v", "hvc1") // libx264
					.done();
			// "-c:v", "libx265", "-preset", "medium", "-crf", "25", "-pix_fmt",
			// "yuv420p10le",
			// "-b:a", "256k", "-tag:v", "hvc1"
			executor = new FFmpegExecutor(new FFmpeg(this.ffmpegPath));
			job = executor.createJob(builder, progress -> System.out.println("Progress: " + progress));
			job.run();
			return tsFolderPath;
		} catch (IOException e) {
			log.error("ffmpeg转换MP4" + inputFilePath + "异常" + e.getMessage());
			throw new ServiceException(e.getMessage());
		}
	}

	/**
	 * 视频转图片
	 * 
	 * @description:
	 * @param filePath
	 * @param targetPath
	 * @return
	 * @author: donghang
	 * @date: 2021年3月17日上午9:24:35
	 * @modify:
	 */
	public String videoToImage(String inputFilePath, String tsFolderPath, String imagePrefix) {
		// 切片文件夹
		File outputDir = new File(tsFolderPath);
		if (!outputDir.exists()) {
			outputDir.mkdirs(); // 创建目录
		}
		try {
			// 1.判断是否需要转换
			FFmpegBuilder builder = null;
			FFmpegExecutor executor = null;
			FFmpegJob job = null;
			// 每100秒一帧，1/100=0.01
			builder = new FFmpegBuilder().addInput(inputFilePath).overrideOutputFiles(true)
					.addOutput(tsFolderPath + "/" + imagePrefix + "-%3d.png")
					.addExtraArgs("-vf", "fps=0.01", "-vframes", "6", "-f", "image2").done();
			executor = new FFmpegExecutor(new FFmpeg(this.ffmpegPath));
			job = executor.createJob(builder, progress -> System.out.println("Progress: " + progress));
			job.run();
			return tsFolderPath;
		} catch (IOException e) {
			log.error("ffmpeg转换图片" + inputFilePath + "异常" + e.getMessage());
			throw new ServiceException(e.getMessage());
		}
	}
}
